/**
 ******************************************************************************
 * @file	fpga-20c.h
 * @brief	fpga-20c 存储器通信

采用原始 fpga-20c SPI通信协议

bug
    fpga 自身返回序列有缺陷，普通的控制命令容易错乱，主控端需要多次重复读取，
    返回OTDR数据是否有错误无法得知，
 *
 @section Platform
    -#
 @section Library
    -#
 *
 * @section Depend
 *	-# spi_mxs.ko
 *	-# spidev.ko

- 2016-10-21,MenglongWu,MenglongWoo@aliyun.com
*/

#ifndef _FPGA_20C_H_
#define _FPGA_20C_H_

/** @defgroup fpga_20c
 * @{
 */
struct fpga_dev
{
    int   fd;    ///<
    char  pid;   ///<
    char *desc;  ///<
};

struct fpga_test_param
{
    unsigned short laser;     ///< 激光器波长，支持1310、1550、1625
    unsigned short pulse;     /*!< 脉冲宽度 @ref 各量程脉冲列表 同一脉宽值在同量程下取值方式不同
                  300m 量程可用脉宽 @ref 脉冲列表300m
                  20Km 量程可用脉宽 @ref 脉冲列表20Km
                  100Km 量程可用脉宽 @ref 脉冲列表 100Km
                  180Km 量程可用脉宽 @ref 脉冲列表180Km */
    unsigned short freq;      ///< 频率选择 @ref 采样时钟选择
    unsigned short adopt_pt;  ///< 采样点数
    unsigned short add_cnt;   ///< 累加次数
    char           amp;       ///< 放大倍数 跨阻 @ref 运放控制
    char           apd_vol;   ///< APD电压  可选电压 @ref APD电压范围
    char           power;     ///< 激光器功率 可选档位 @ref 光功率控制
    char           isrun;     ///< 是否启动
};

/** @defgroup 各量程脉冲列表
* @{
* @brief	每个量程下脉冲宽度与 @ref 采样时钟选择 有直接关系
*
* 例如TP_PULSE_100KM_5120_NS与TP_PULSE_180KM_10240_NS对应的值均是128，但生成的
* 脉冲宽度不同，本质在于两100Km量程下采样始终25MHz，180Km量程12MHz

<table>
<tr><th>量程(km) <th>采样频率(MHz) 	<th>采样时间(ms)	<th>光往返时间(ms)	<th>脉冲周期(ms)	<th>1s内单个时钟对应的累加次数
<tr><td>1	<td>  800		<td>0.04		<td>0.01		<td>0.1 		<td>10000
<tr><td>5	<td>  400		<td>0.08		<td>0.05		<td>0.3125 		<td>3200
<tr><td>10	<td>  200		<td>0.16		<td>0.1			<td>0.5			<td>2000
<tr><td>30	<td>  100		<td>0.32		<td>0.3			<td>1 			<td>1000
<tr><td>60	<td>  50		<td>0.64		<td>0.6			<td>1			<td>1000
<tr><td>100	<td>  25		<td>1.28		<td>1			<td>2.666 		<td>375
<tr><td>200	<td>  12.5		<td>2.56		<td>2			<td>2.666		<td>375
</table>
*/

/** @defgroup 脉冲列表300m
 * @{
 */

#define TP_PULSE_300M_5_NS      (0x5555)  ///<
#define TP_PULSE_300M_10_NS     (0)       ///<
#define TP_PULSE_300M_20_NS     (1)       ///<
#define TP_PULSE_300M_40_NS     (2)       ///<
/**
 * @}
 */

/** @defgroup 脉冲列表1Km
 * @{
 */
#define TP_PULSE_1KM_5_NS       (TP_PULSE_300M_5_NS)
#define TP_PULSE_1KM_10_NS      (0)  ///< 实际20ns
#define TP_PULSE_1KM_20_NS      (1)  ///<
#define TP_PULSE_1KM_40_NS      (2)  ///<
/**
 * @}
 */

/** @defgroup 脉冲列表5Km
 * @{
 */
#define TP_PULSE_5KM_5_NS       (TP_PULSE_300M_5_NS)
#define TP_PULSE_5KM_10_NS      (0)  ///< 实际20ns
#define TP_PULSE_5KM_20_NS      (1)  ///<
#define TP_PULSE_5KM_40_NS      (2)  ///<
#define TP_PULSE_5KM_80_NS      (4)  ///<
#define TP_PULSE_5KM_160_NS     (8)  ///<
/**
 * @}
 */

/** @defgroup 脉冲列表10Km
 * @{
 */
#define TP_PULSE_10KM_5_NS      (0x5555)  ///<
#define TP_PULSE_10KM_10_NS     (0)       ///< 实际20ns
#define TP_PULSE_10KM_20_NS     (1)       ///<
#define TP_PULSE_10KM_40_NS     (2)       ///<
#define TP_PULSE_10KM_80_NS     (4)       ///<
#define TP_PULSE_10KM_160_NS    (8)       ///<
#define TP_PULSE_10KM_320_NS    (16)      ///<
/**
 * @}
 */

/** @defgroup 脉冲列表30Km
 * @{
 */
#define TP_PULSE_30KM_5_NS      (0x5555)  ///<
#define TP_PULSE_30KM_10_NS     (0)       ///< 实际20ns
#define TP_PULSE_30KM_20_NS     (1)       ///<
#define TP_PULSE_30KM_40_NS     (2)       ///<
#define TP_PULSE_30KM_80_NS     (4)       ///<
#define TP_PULSE_30KM_160_NS    (8)       ///<
#define TP_PULSE_30KM_320_NS    (16)      ///<
#define TP_PULSE_30KM_640_NS    (32)      ///< 对对对
/**
 * @}
 */

/** @defgroup 脉冲列表60Km
 * @{
 */
#define TP_PULSE_60KM_40_NS     (2)   ///<
#define TP_PULSE_60KM_80_NS     (4)   ///<
#define TP_PULSE_60KM_160_NS    (8)   ///<
#define TP_PULSE_60KM_320_NS    (16)  ///<
#define TP_PULSE_60KM_640_NS    (32)  ///<
#define TP_PULSE_60KM_1280_NS   (64)  ///<
/**
 * @}
 */

/** @defgroup 脉冲列表100Km
 * @{
 */
#define TP_PULSE_100KM_160_NS   (4)    ///<
#define TP_PULSE_100KM_320_NS   (8)    ///<
#define TP_PULSE_100KM_640_NS   (16)   ///<
#define TP_PULSE_100KM_1280_NS  (32)   ///<
#define TP_PULSE_100KM_2560_NS  (64)   ///<
#define TP_PULSE_100KM_5120_NS  (128)  ///<
#define TP_PULSE_100KM_10240_NS (256)  ///<
#define TP_PULSE_100KM_20480_NS (512)  ///<
/**
 * @}
 */

/** @defgroup 脉冲列表180Km
 * @{
 */
#define TP_PULSE_180KM_160_NS   (2)    //(2) ///<
#define TP_PULSE_180KM_320_NS   (4)    //(4)///<
#define TP_PULSE_180KM_640_NS   (8)    //(8)///<
#define TP_PULSE_180KM_1280_NS  (16)   //(16) ///<
#define TP_PULSE_180KM_2560_NS  (32)   //(32) ///<
#define TP_PULSE_180KM_5120_NS  (64)   //(64) ///<
#define TP_PULSE_180KM_10240_NS (128)  //(128) ///<
#define TP_PULSE_180KM_20480_NS (256)  //(256) ///<
/**
 * @}
 */

/** end 各量程脉冲列表
 * @}
 */


/** @defgroup 采样时钟选择
 * @{
 */
#define TP_FREQ_800             (800)
#define TP_FREQ_400             (400)
#define TP_FREQ_200             (200)
#define TP_FREQ_100             (100)
#define TP_FREQ_50              (50)
#define TP_FREQ_25              (25)
#define TP_FREQ_12              (12)
#define TP_FREQ_6               (6)

#define TP_FREQ_300M            TP_FREQ_800
#define TP_FREQ_1KM             TP_FREQ_800
#define TP_FREQ_5KM             TP_FREQ_400
#define TP_FREQ_10KM            TP_FREQ_200
#define TP_FREQ_30KM            TP_FREQ_100
#define TP_FREQ_60KM            TP_FREQ_50
#define TP_FREQ_100KM           TP_FREQ_25
#define TP_FREQ_180KM           TP_FREQ_12
#define TP_FREQ_200KM           TP_FREQ_12

/** end 采样时钟选择
 * @}
 */
#define TP_AMP1_S1_ON           ((unsigned long)(0))
#define TP_AMP1_S2_ON           ((unsigned long)(0))
#define TP_AMP1_S3_ON           ((unsigned long)(0))

#define TP_AMP1_S1_OFF          ((unsigned long)(0x01))
#define TP_AMP1_S2_OFF          ((unsigned long)(0x02))
#define TP_AMP1_S3_OFF          ((unsigned long)(0x04))


/** @defgroup 运放控制
 * @{
 * @brief	运放4个开关
 *
 * 跨阻和APD电压选择模式。S1~S3控制跨阻，S4控制二级放大倍数
 * S1~S3控制的电阻分别为10K，51K，200K，低电平有效，例如S1为0互阻为10K。S4控制二
 * 级放大倍数,S4为1放大倍数4倍，S4为0放大倍数1倍。
 */

/** @defgroup 运放控制开关1-3
 * @{
 */
#define TP_AMP1_ONLY_S1         (TP_AMP1_S1_ON | TP_AMP1_S2_OFF | TP_AMP1_S3_OFF)  ///< 1级运放只启用开关1
#define TP_AMP1_ONLY_S2         (TP_AMP1_S2_ON | TP_AMP1_S1_OFF | TP_AMP1_S3_OFF)  ///< 1级运放只启用开关2
#define TP_AMP1_ONLY_S3         (TP_AMP1_S3_ON | TP_AMP1_S1_OFF | TP_AMP1_S2_OFF)  ///< 1级运放只启用开关3
/** end 运放控制开关1-3
 * @}
 */

/** @defgroup 运放控制开关4
 * @{
 */
#define TP_AMP2_S4_ON           (unsigned long)(0)     ///< 打开2级运放
#define TP_AMP2_S4_OFF          (unsigned long)(0x08)  ///< 关闭2级运放
/** end 运放控制开关4
 * @}
 */


#define TP_AMP1(n)              (n & 0x07)  ///< 运放1级放大 取值范围 @ref 运放控制开关1-3
#define TP_AMP2(n)              (n & 0x08)  ///< 运放2级放大 取值范围 @ref 运放控制开关4

#define TP_AMP(p1, p2)          (TP_AMP1(p1) + TP_AMP2(p2))  ///< 1-2级运放设置 取值范围分别是@ref 运放控制开关1-3 @ref 运放控制开关4
/** end 运放控制
 * @}
 */


#define TP_APD_S5_ON            (unsigned char)(0x10)
#define TP_APD_S6_ON            (unsigned char)(0x20)
#define TP_APD_S5_OFF           (unsigned char)((~TP_APD_S5_ON) & 0x30)
#define TP_APD_S6_OFF           (unsigned char)((~TP_APD_S6_ON) & 0x30)
/** @defgroup APD电压范围
 * @{
 * @brief	APD 电压选择开关
 *
 * APD电压选择模式。S5，S6控制APD电压。S5~S6控制APD电压S5为1时放大倍数高，
 * S6为1时放大倍数接近为1不放大。
 */
#define TP_APD_39V              (unsigned char)(TP_APD_S5_ON | TP_APD_S6_OFF)  ///< APD 39V
#define TP_APD_30V              (unsigned char)(TP_APD_S5_ON | TP_APD_S5_OFF)  ///< APD 30V
/**
 * @}
 */


/** @defgroup 光功率控制
 * @{
 */
#define OTDR_LASER_PW_LV1       1                  ///< 激光器功率 Level1 最小功率
#define OTDR_LASER_PW_LV2       2                  ///< 激光器功率 Level2
#define OTDR_LASER_PW_LV3       3                  ///< 激光器功率 Level3
#define OTDR_LASER_PW_LV4       4                  ///< 激光器功率 Level4 最大功率
#define OTDR_LASER_PW_HIGH      OTDR_LASER_PW_LV4  ///< 激光器功率 最大功率
#define OTDR_LASER_PW_LOW       OTDR_LASER_PW_LV1  ///< 激光器功率 最大功率
/**
 * @}
 */


/** @defgroup 红光模式
 * @{
 */
#define OTDR_RL_OFF             (0)  ///< 关闭红光
#define OTDR_RL_ON              (1)  ///< 红光常亮 1.2ms高电平，3.7ms低电平
#define OTDR_RL_1HZ             (2)
#define OTDR_RL_10HZ            (3)
#define OTDR_RL_SLOW            OTDR_RL_1HZ   ///< 红光慢闪烁 1HZ 500ms高电平，500ms低电平
#define OTDR_RL_FAST            OTDR_RL_10HZ  ///< 红光快闪烁 10HZ 100ms高电平，100ms低电平
/**
 * @}
 */

/** @defgroup 低功耗模式
 * @{
 */
#define OTDR_LOW_POWER          (0) /*!< 低功耗 */
#define OTDR_OFF_POWER          (1) /*!< 关闭电源，此电源是处理器总电源，如果存在ARM与FPGA同时控制该电源， \
                                                 则先FPGA关断，后ARM关断*/
/**
 * @}
 */


/** @defgroup 通信光状态
 * @{
 */
#define COM_LASER               (1)                      ///< 存在通信光
#define COM_FREE                (2)                      ///< 无通信光
#define IS_COM_FREE(n)          (n == COM_FREE ? 0 : 1)  ///< OTDR 可自由发光
/**
 * @}
 */


/** @defgroup FPGA导出函数
 * @{
 */


/**
 * @brief	打开OTDR采集卡，设备挂在SPI总线上
 * @param[in]	device 设备节点
 * @param[out]	dev 设备喵师傅
 * @param[in]	ispeed 指定通信速率，传递0时采用默认500KHz
 * @retval	0  成功 dev返回有效值
 * @retval	-1 设备节点打开失败
 * @retval	-2 设备打开成功，但检测不到FPGA
 * @see fpga_close
 */
int fpga_open(char *device, struct fpga_dev **dev, unsigned long ispeed);

/**
 * @brief	关闭已打开的otdr采集卡
 * @param[in]	dev 设备描述符
 * @retval	null
 * @see fpga_open
 */
int fpga_close(struct fpga_dev *dev);

/**
 * @brief	无用
 * @param[in]	dev 设备描述符
 * @param[in]	val 测试参数
 *		默认各量程测试参数填充 @ref 构建默认测试参数 可在默认基础上做修改
 * @retval	null
 * @remarks
 * @see fpga_read_ad
 */
unsigned int fpga_request_test(struct fpga_dev *dev, struct fpga_test_param *val);

/**
 * @brief	红光输出控制
 * @param[in]	dev 设备描述符
 * @param[in]	val 红光模式
 *		模式选择范围 @ref 红光模式
 * @retval	null
 * @remarks 该命令FPGA没有返回值，永远认为成功
 */
unsigned int fpga_red_laser(struct fpga_dev *dev, int mode);

/**
 * @brief	（作废）调节LCD背光
 * @param[in]	dev 设备描述符
 * @param[in]	val lcd 背光输出频率
 * @retval	null
 * @remarks
 * @see
 */
unsigned int fpga_lcd_bl(struct fpga_dev *dev, int val);

/**
 * @brief	（作废）获取电池状态
 * @param[in]	dev 设备描述符
 * @param[in]	status 状态
 * @retval	null
 * @remarks
 * @see
 */
unsigned int fpga_charge_status(struct fpga_dev *dev, char *status);

/**
 * @brief	fpga电源模式
 * @param[in]	dev 设备描述符
 * @param[out]	mode 选择电源模式
 *		模式选择范围 @ref 低功耗模式
 * @retval	null
 * @remarks	该命令FPGA没有返回值，永远认为成功
 * 		当选择关闭电源模式OTDR_OFF_POWER时，处理器端必须保证其数据安全保存
 */
unsigned int fpga_low_power(struct fpga_dev *dev, int mode);

/**
 * @brief	通信光检测
 * @param[in]	dev 设备描述符
 * @param[out]	status 光路通信状态
 * @retval	0 SPI正常，此时val可以是如下值 @ref 通信光状态
        可通过 IS_COM_FREE 判断
 * @retval	-1 SPI异常
 * @remarks
 * @see IS_COM_FREE
 */
unsigned int fpga_com_laser(struct fpga_dev *dev, int *status);

/**
 * @brief	读取fpga采样结果，每个采样点已32bit存储
 * @param[in]	dev 设备描述符
 * @param[out]	pt 采样点
 * @param[in]	len 采样点长度
 * @remarks	数据组成格式:以下均为16进制\n
 * 		66 23 aa bb cc 23 aa bb cc 23 aa bb cc\n
 * 		其中 66 表示数据已经准备完毕 \n
 * 		23 表示数据分割符\n
 * 		aa bb cc 是单个点累加若干次的结果，具体累加次数由 fpga_request_test 提供
 * 		转换成24byte后小端处理器需要将其转换字节序  0x00ccbbaa
 * @retval	-2 数据没有准备好
 * @retval	0 准备完毕
 * @see	fpga_request_test
 */
unsigned int fpga_read_ad(struct fpga_dev *dev, unsigned long *pt, unsigned long len);

/** @defgroup 构建默认测试参数
 * @{
 * @brief	为何存在自动配置
 *
 * 所谓的自动配置并不是真的自动配置，而是因为采样时钟测量距离、测量脉宽之间
 * 关系密切，所以启动一个测试量程测试前先用对应的 AUTO_BUILD_xxx 构造结构体
 * struct fpga_test_param 模板，然后再根据需要做细微修改，如激光器(laser)、运放
 * (amp)、APD电压(apd)等
 *
 * @see 各量程脉冲列表
 * @see 采样时钟选择
 */
#define AUTO_BUILD_300M(ptr)                                                 \
    {                                                                        \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;           \
	p->laser                  = 1310;                                    \
	p->pulse                  = TP_PULSE_1KM_40_NS;                      \
	p->freq                   = TP_FREQ_1KM;                             \
	p->adopt_pt               = 32000;                                   \
	p->add_cnt                = 10000;                                   \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S1, TP_AMP2_S4_OFF); \
	p->apd_vol                = TP_APD_39V;                              \
	p->power                  = OTDR_LASER_PW_LV1;                       \
	p->isrun                  = 1;                                       \
    }  ///< 默认 300M 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_1KM(ptr)                                                 \
    {                                                                       \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;          \
	p->laser                  = 1310;                                   \
	p->pulse                  = TP_PULSE_5KM_160_NS;                    \
	p->freq                   = TP_FREQ_5KM;                            \
	p->adopt_pt               = 32000;                                  \
	p->add_cnt                = 10000;                                  \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S1, TP_AMP2_S4_ON); \
	p->apd_vol                = TP_APD_39V;                             \
	p->power                  = OTDR_LASER_PW_LV2;                      \
	p->isrun                  = 1;                                      \
    }  ///< 默认 1KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_5KM(ptr)                                                 \
    {                                                                       \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;          \
	p->laser                  = 1310;                                   \
	p->pulse                  = TP_PULSE_5KM_160_NS;                    \
	p->freq                   = TP_FREQ_5KM;                            \
	p->adopt_pt               = 32000;                                  \
	p->add_cnt                = 10000;                                  \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S2, TP_AMP2_S4_ON); \
	p->apd_vol                = TP_APD_39V;                             \
	p->power                  = OTDR_LASER_PW_LV2;                      \
	p->isrun                  = 1;                                      \
    }  ///< 默认 5KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_10KM(ptr)                                                \
    {                                                                       \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;          \
	p->laser                  = 1310;                                   \
	p->pulse                  = TP_PULSE_10KM_320_NS;                   \
	p->freq                   = TP_FREQ_10KM;                           \
	p->adopt_pt               = 32000;                                  \
	p->add_cnt                = 10000;                                  \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S2, TP_AMP2_S4_ON); \
	p->apd_vol                = TP_APD_39V;                             \
	p->power                  = OTDR_LASER_PW_LV2;                      \
	p->isrun                  = 1;                                      \
    }  ///< 默认 10KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_60KM(ptr)                                                \
    {                                                                       \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;          \
	p->laser                  = 1310;                                   \
	p->pulse                  = TP_PULSE_60KM_1280_NS;                  \
	p->freq                   = TP_FREQ_60KM;                           \
	p->adopt_pt               = 32000;                                  \
	p->add_cnt                = 10000;                                  \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S2, TP_AMP2_S4_ON); \
	p->apd_vol                = TP_APD_39V;                             \
	p->power                  = OTDR_LASER_PW_LV3;                      \
	p->isrun                  = 1;                                      \
    }  ///< 默认 60KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_100KM(ptr)                                               \
    {                                                                       \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;          \
	p->laser                  = 1310;                                   \
	p->pulse                  = TP_PULSE_100KM_10240_NS;                \
	p->freq                   = TP_FREQ_100KM;                          \
	p->adopt_pt               = 32000;                                  \
	p->add_cnt                = 10000;                                  \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S3, TP_AMP2_S4_ON); \
	p->apd_vol                = TP_APD_39V;                             \
	p->power                  = OTDR_LASER_PW_LV3;                      \
	p->isrun                  = 1;                                      \
    }  ///< 默认 100KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_180KM(ptr)                                               \
    {                                                                       \
	struct fpga_test_param *p = (struct fpga_test_param *)ptr;          \
	p->laser                  = 1310;                                   \
	p->pulse                  = TP_PULSE_180KM_20480_NS;                \
	p->freq                   = TP_FREQ_180KM;                          \
	p->adopt_pt               = 32000;                                  \
	p->add_cnt                = 10000;                                  \
	p->amp                    = TP_AMP(TP_AMP1_ONLY_S3, TP_AMP2_S4_ON); \
	p->apd_vol                = TP_APD_39V;                             \
	p->power                  = OTDR_LASER_PW_LV4;                      \
	p->isrun                  = 1;                                      \
    }  ///< 默认 200KM 配置配置参数，填充 fpga_test_param
/** end 构建默认测试参数
 * @}
 */

/** end FPGA导出函数
 * @}
 */


/** end fpga_20c
 * @}
 */
#endif
